package com.icesoft.framework.core.util;

import com.icesoft.framework.core.util.functions.Function2;

import java.util.*;
import java.util.function.Function;

/**
 * List帮助
 *
 * @author LKQ
 * @create 2022/3/4 17:43
 */
@SuppressWarnings("unused")
public class ListUtil {

	public static <T> boolean isNotEmpty(Collection<T> list) {
		return !Objects.isNull(list) && !list.isEmpty();
	}

	public static <T> boolean isEmpty(Collection<T> list) {
		return Objects.isNull(list) || list.isEmpty();
	}

	public static <T> boolean isNotEmpty(T[] array) {
		return !Objects.isNull(array) && array.length > 0;
	}

	public static <T> boolean isEmpty(T[] array) {
		return Objects.isNull(array) || array.length <= 0;
	}

	public static <T> List<T> emptyList() {
		return Collections.emptyList();
	}

	/**
	 * List添加方法，
	 * <pre>
	 *     若 list == null list = new Array
	 *     若 item == null list = new Array 不添加子项
	 * </pre>
	 * <p style="color:red">注意：不可对象属性引用使用 如 ListHelper.add(r.getItems())</p>
	 * list
	 *
	 * @param list 待添加数据的list
	 * @param item 添加的子项
	 * @param <T>  类型
	 */
	public static <T> List<T> add(List<T> list, T item) {
		if (isEmpty(list)) {
			list = new ArrayList<>();
		}
		if (!Objects.isNull(item)) {
			list.add(item);
		}
		return list;
	}

	public static <T> Set<T> add(Set<T> list, T item) {
		if (isEmpty(list)) {
			list = new HashSet<>();
		}
		if (!Objects.isNull(item)) {
			list.add(item);
		}
		return list;
	}

	/**
	 * @param list    待处理数据
	 * @param delList 待删除数据
	 */
	public static <T> void del(List<String> list, String... delList) {
		if (Objects.isNull(delList)) {
			return;
		}
		List<String> nameList = Arrays.asList(delList);
		list.removeIf(nameList::contains);
	}

	/**
	 * @param list    待处理数据
	 * @param func    数据转换
	 * @param delList 待删除数据
	 */
	@SafeVarargs
	public static <T, F> void del(List<T> list, Function<T, F> func, F... delList) {
		if (Objects.isNull(delList)) {
			return;
		}
		List<F> nameList = Arrays.asList(delList);
		list.removeIf(t -> nameList.contains(func.apply(t)));
	}

	/**
	 * 自定义转换
	 *
	 * @param list List源
	 * @param func 转换函数
	 * @param <T>  目标
	 * @return List目标
	 */
	public static <T> List<T> find(List<T> list, Function<T, Boolean> func) {
		List<T> tmp = new ArrayList<>();
		if (isNotEmpty(list)) {
			for (T t : list) {
				if (func.apply(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	public static <T> T getFirst(List<T> list) {
		return get(list, 0);
	}

	public static <T> T getLast(List<T> list) {
		return get(list, list.size());
	}

	/**
	 * 获取list中第index的数据
	 * <pre>
	 *     list == null return null
	 *     0 > index >= list.size() return last
	 * </pre>
	 *
	 * @param list  数据
	 * @param index 下标 0开始 至  (list.size() - 1)
	 */
	public static <T> T get(List<T> list, int index) {
		if (isEmpty(list)) {
			return null;
		}
		if (index >= list.size() || index < 0) {
			index = list.size() - 1;
		}
		return list.get(index);
	}

	public static <T> T getFirst(Set<T> list) {
		return get(list, 0);
	}

	public static <T> T getLast(Set<T> list) {
		return get(list, list.size());
	}

	/**
	 * 获取list中第index的数据
	 * <pre>
	 *     list == null return null
	 *     0 > index >= list.size() return last
	 * </pre>
	 *
	 * @param list  数据
	 * @param index 下标 0开始 至  (list.size() - 1)
	 */
	public static <T> T get(Set<T> list, int index) {
		if (isEmpty(list)) {
			return null;
		}
		if (index >= list.size() || index < 0) {
			index = list.size() - 1;
		}
		return (new ArrayList<>(list)).get(index);
	}

	public static List<String> format(String str) {
		return format(str, s -> s.split(","));
	}

	public static List<String> format(String str, Function<String, String[]> func) {
		if (StringUtils.isNotEmpty(str)) {
			return Arrays.asList(func.apply(str));
		}
		return null;
	}


	/**
	 * 自定义转换
	 *
	 * @param list List源
	 * @param func 转换函数
	 * @param <T>  目标
	 * @param <F>  源
	 * @return List目标
	 */
	public static <T, F> List<T> format(List<F> list, Function<F, T> func) {
		List<T> tmp = new ArrayList<>();
		if (isNotEmpty(list)) {
			for (F f : list) {
				T t = func.apply(f);
				if (!Objects.isNull(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	/**
	 * 自定义转换
	 *
	 * @param list     List源
	 * @param findFunc 查找函数
	 * @param func     转换函数
	 * @param <T>      目标
	 * @param <F>      源
	 * @return List目标
	 */
	public static <T, F> List<T> format(List<F> list, Function<F, Boolean> findFunc, Function<F, T> func) {
		List<T> tmp = new ArrayList<>();
		if (isNotEmpty(list)) {
			for (F f : list) {
				if (findFunc.apply(f)) {
					T t = func.apply(f);
					if (!Objects.isNull(t)) {
						tmp.add(t);
					}
				}
			}
		}
		return tmp;
	}

	public static <T, F> Set<T> format2Set(List<F> list, Function<F, T> func) {
		Set<T> tmp = new HashSet<>();
		if (isNotEmpty(list)) {
			for (F f : list) {
				T t = func.apply(f);
				if (!Objects.isNull(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	/**
	 * 将Map转为List
	 *
	 * @param map  数据源
	 * @param func 转换函数
	 * @param <T>  目标对象
	 * @param <K>  map-key
	 * @param <V>  map-val
	 * @return List-T
	 */
	public static <T, K, V> List<T> format(Map<K, V> map, Function2<K, V, T> func) {
		List<T> tmp = new ArrayList<>();
		if (!Objects.isNull(map)) {
			for (Map.Entry<K, V> entry : map.entrySet()) {
				T t = func.apply(entry.getKey(), entry.getValue());
				if (!Objects.isNull(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	public static <T, K, V> List<T> format(Map<K, V> map, Function<Map.Entry<K, V>, Boolean> findFunc, Function2<K, V, T> func) {
		List<T> tmp = new ArrayList<>();
		if (!Objects.isNull(map)) {
			for (Map.Entry<K, V> entry : map.entrySet()) {
				if (findFunc.apply(entry)) {
					T t = func.apply(entry.getKey(), entry.getValue());
					if (!Objects.isNull(t)) {
						tmp.add(t);
					}
				}
			}
		}
		return tmp;
	}

	public static <T, K, V> Set<T> format2Set(Map<K, V> map, Function2<K, V, T> func) {
		Set<T> tmp = new HashSet<>();
		if (!Objects.isNull(map)) {
			for (Map.Entry<K, V> entry : map.entrySet()) {
				T t = func.apply(entry.getKey(), entry.getValue());
				if (!Objects.isNull(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	/**
	 * 去重重复
	 *
	 * @param list 数据源
	 * @param func 转换方法
	 * @param <T>  结果实体
	 * @param <F>  来源实体
	 * @return 经过func转换后去重重复的数据
	 */
	public static <T, F> List<T> formatOnly(List<F> list, Function<F, T> func) {
		List<T> tmp = new ArrayList<>();
		if (isNotEmpty(list)) {
			for (F f : list) {
				T t = func.apply(f);
				if (!Objects.isNull(t) && !tmp.contains(t)) {
					tmp.add(t);
				}
			}
		}
		return tmp;
	}

	public static List<Integer> format2Int(List<String> list) {
		return format(list, Integer::parseInt);
	}

	public static List<Long> format2Long(List<String> list) {
		return format(list, Long::parseLong);
	}

	public static List<String> format2Str(List<Integer> list) {
		return format(list, String::valueOf);
	}

	public static Set<Integer> format2IntSet(List<String> list) {
		return format2Set(list, Integer::parseInt);
	}

	public static Set<Long> format2LongSet(List<String> list) {
		return format2Set(list, Long::parseLong);
	}

	public static Set<String> format2StrSet(List<Integer> list) {
		return format2Set(list, String::valueOf);
	}

	/**
	 * List 数据拼接 以","分割
	 *
	 * @return ["A","B","C"] => A,B,C  [1,2,3] => 1,2,3
	 */
	public static String toString2(List<?> list) {
		return StringUtils.join(list, ",");
	}

	public static <T> String toString2(T[] arrea) {
		return StringUtils.join(arrea, ",");
	}

	/**
	 * 将数据等长拆分 类型拆分见MapUtil
	 *
	 * @param list 数据
	 * @param len  拆分长度
	 * @return 拆分后的数据
	 */
	public static <T> List<List<T>> sub(List<T> list, int len) {
		List<List<T>> tmp = new ArrayList<>();
		for (int i = 0; i < list.size(); i += len) {
			tmp.add(list.subList(i, Math.min(i + len, list.size())));
		}
		return tmp;
	}

	//======================================集合运算

	/**
	 * 交集
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> jiao(List<T> list, List<T>... list2) {
		List<T> jiao = new ArrayList<>();
		if (!Objects.isNull(list2)) {
			for (List<T> l : list2) {
				if (isEmpty(l)) {
					continue;
				}
				for (T t : l) {
					if (list.contains(t)) {
						jiao.add(t);
					}
				}
			}
		}
		return jiao;
	}

	/**
	 * 并集
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> bing(List<T> list, List<T>... list2) {
		List<T> bing = new ArrayList<>(list);
		if (!Objects.isNull(list2)) {
			for (List<T> l : list2) {
				if (isEmpty(l)) {
					continue;
				}
				bing.addAll(l);
			}
		}
		return bing;
	}

	/**
	 * 差集
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> cha(List<T> list, List<T>... list2) {
		List<T> bing = new ArrayList<>(list);
		if (!Objects.isNull(list2)) {
			for (List<T> l : list2) {
				if (isEmpty(l)) {
					continue;
				}
				bing.removeAll(l);
			}
		}
		return bing;
	}

	/**
	 * 并-交
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> feiJiao(List<T> list, List<T>... list2) {
		List<T> bing = bing(list, list2);
		List<T> jiao = jiao(list, list2);
		bing.removeAll(jiao);
		return bing;
	}

	/**
	 * 去重
	 *
	 * @param list 集合
	 */
	public static <T> List<T> distinct(List<T> list) {
		return new LinkedList<>(new LinkedHashSet<>(list));
	}


	/**
	 * 交集 去重
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> jiaoDistinct(List<T> list, List<T>... list2) {
		return distinct(jiao(list, list2));
	}

	/**
	 * 并集 去重
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> bingDistinct(List<T> list, List<T>... list2) {
		return distinct(bing(list, list2));
	}

	/**
	 * 差集 去重
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> chaDistinct(List<T> list, List<T>... list2) {
		return distinct(cha(list, list2));
	}

	/**
	 * 并-交 去重
	 *
	 * @param list  集合
	 * @param list2 集合
	 */
	@SafeVarargs
	public static <T> List<T> feiJiaoDistinct(List<T> list, List<T>... list2) {
		return distinct(feiJiao(list, list2));
	}

	/**
	 * 统计数量
	 */
	public static <T> Map<T, Integer> total(List<T> list) {
		Map<T, Integer> totalMap = new LinkedHashMap<>();
		if (isEmpty(list)) {
			return totalMap;
		}
		for (T t : list) {
			if (t == null) {
				continue;
			}
			if (totalMap.containsKey(t)) {
				totalMap.put(t, totalMap.get(t) + 1);
			} else {
				totalMap.put(t, 1);
			}
		}
		return totalMap;
	}

	/**
	 * 统计数量
	 *
	 * @param func 转换函数
	 */
	public static <T, R> Map<R, Integer> total(List<T> list, Function<T, R> func) {
		Map<R, Integer> totalMap = new LinkedHashMap<>();
		if (isEmpty(list)) {
			return totalMap;
		}
		int num;
		for (T t : list) {
			if (t == null) {
				continue;
			}
			R key = func.apply(t);
			if (StringUtils.isNotEmpty(key)) {
				if (totalMap.containsKey(key)) {
					num = totalMap.get(key) + 1;
				} else {
					num = 1;
				}
				totalMap.put(key, num);
			}
		}
		return totalMap;
	}

	public static void main(String[] args) {
//        List<Integer> list;
//        list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
//        System.out.println(sub(list, 5));
//        System.out.println(sub(list, 3));
//
//        list = format(list, t -> t > 3 ? t : null);
//        System.out.println(list);
//
//        list = format(list, t -> 0);
//        System.out.println(list);
//
//        list = format(null, t -> null);
//        System.out.println(list);

//        List<Integer> list = new ArrayList<>(Arrays.asList(5,2,4,1,3));
//        List<Integer> list2 = new ArrayList<>(Arrays.asList(1,12,3,4,15));
//        System.out.println(list);
//        System.out.println(list2);
//        System.out.println("交集：" + jiao(list, list2));
//        System.out.println("交集（去重）：" + jiaoDistinct(list, list2));
//        System.out.println("并集：" + bing(list, list2));
//        System.out.println("并集（去重）：" + bingDistinct(list, list2));
//        System.out.println("差集：" + cha(list, list2));
//        System.out.println("差集（去重）：" + chaDistinct(list, list2));
//        System.out.println("并-差：" + feiJiao(list, list2));
//        System.out.println("并-差（去重）：" + feiJiaoDistinct(list, list2));
	}


}
